home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------*
- | sort.c - Unix-like utility. |
- | Syntax: sort [flags] [file [file [ ... ] ] |
- | Sorts the given files (or stdin) to stdout; |
- | see Syntax() for a complete description. |
- | v1.00 MLO 911225 |
- *---------------------------------------------*/
-
- /**
- | For sorting, the read lines are arranged in memory in a binary tree;
- | the tree itself can be balanced (if BALANCED_TREE is defined),
- | according to the algorithm of Adel'son-Vel'skij and Landis as
- | described from D.E.Knuth - The art of computer programming (Addison
- | Wesley) - Vol. 3, pag. 451-471. This leads to a more efficient
- | searching along the tree for unbalanced input (i.e. for almost
- | already sorted files), but is an exercise without pratical effect
- | normally; so you would leave BALANCED_TREE undefined.
- |
- | #define'ing SIMPLE generates a short version of sort, with the
- | normal binary tree algorithm, and alphabetical ordering from column
- | 1 as only ordering option (the only active switch is -r). This way,
- | a file containing 1202 lines of ASCII text (47100 bytes total) can
- | be sorted on a vanilla A500 in less than 4 seconds, against the 24
- | seconds needed from c:sort (AmigaDOS 1.3: Kickstart 34.5, Workbench
- | 34.28).
- **/
-
- #include <stdio.h>
- #include <stdlib.h>
- #ifndef SIMPLE
- #include <string.h>
- #include <ctype.h>
- #endif
- #include <libraries/dos.h>
- #include <proto/exec.h>
- #include "mlo.h"
- #include "sort.h"
-
- short int abortProg = 0; /* "CTRL-C hit" flag */
- Boolean reverse = False; /* "Sort in reverse order" flag */
-
- FILE *fp = NULL;
-
- #ifndef SIMPLE
- static SortType method = ALPHABETICAL; /* "Sort method" flag */
- static SortType divide = COLUMN; /* "Input line division" flag */
- static char terminator[TERM_LEN] = " "; /* Field separator(s) */
- static int start = 0; /* Sorting Field | Column number */
- char *temp1 = NULL; /* Temporary buffers */
- static char *temp2;
- #endif
-
- Node *root = NULL; /* Binary tree root */
-
- #ifdef BALANCED_TREE
- Node *critical; /* Critical node for rebalancing */
- Node *father; /* Father node of *critical */
- #endif
-
- static void DoTheStuff(FILE *filePointer);
- static void Syntax(void);
-
- void main(
- int argc,
- char **argv
- ){
-
- /**
- | Resolves the input line
- **/
-
- while (--argc) {
- if ( ((*++argv)[0] == '-') ) {
- switch ((*argv)[1]) {
- case 'r':
- case 'R':
- reverse = True;
- break;
-
- #ifdef SIMPLE
- default:
- Syntax();
- }
- #else
- case 'f':
- case 'F':
- method = CASE_FOLDED;
- break;
- case 'n':
- case 'N':
- method = NUMERICAL;
- break;
- case 't':
- case 'T':
- if ((*argv)[2]) strcpy(terminator, *argv+2);
- else Syntax();
- break;
- default:
- if (isdigit((*argv)[1])) start = atoi(*argv+1) - 1;
- else Syntax();
- divide = COLUMN;
- break;
- }
- } else if ((*argv)[0] == '+') {
- if (isdigit((*argv)[1])) start = atoi(*argv+1);
- else Syntax();
- divide = FIELD;
- #endif
-
- } else if ((*argv)[0] == '?') {
- Syntax();
- } else {
- break;
- }
- }
-
- /**
- | Allocate the temporary buffers
- **/
-
- #ifndef SIMPLE
- if ((temp1 = calloc(2, LINE_LENGTH)) == NULL) {
- puts("sort: couldn't obtain heap memory.");
- exit(SYS_ABORT_CODE);
- }
- temp2 = temp1 + LINE_LENGTH;
- #endif
-
- /**
- | Reads and sorts the input file(s)
- **/
-
- if (argc) {
- while (argc--) {
- if ((fp = fopen(*argv, "r")) == NULL) {
- printf("sort: couldn't open file \"%s\".\n", *argv);
- } else {
- DoTheStuff(fp);
- fclose(fp);
- fp = NULL;
- }
- ++argv;
- }
- } else {
- DoTheStuff(stdin);
- }
-
- /**
- | Final printout, and graceful exit
- **/
-
- if (root) PrintTree(root);
-
- #ifndef SIMPLE
- free(temp1);
- #endif
-
- exit(SYS_NORMAL_CODE);
- }
-
- #ifndef SIMPLE
- int Compare(
- char *p1,
- char *p2
- ){
- int result;
-
- /**
- | Compares the two string in "p1" and "p2"; returns 0 if they
- | are identical, otherwise compares them using the sorting
- | criteria specified in the input line, returning a negative
- | number if "p1" comes before "p2" or a positive number otherwise.
- |
- | Are the string absolutely identical?
- **/
-
- if (!strcmp(p1, p2)) return 0;
-
- /**
- | If not, store in p1 and p2 the pointers to the string regions
- | to be compared.
- **/
-
- switch (divide) {
- case COLUMN:
- p1 += start;
- p2 += start;
- break;
- case FIELD:
- if (*terminator == BLANK) {
- GetTokBlk(p1, start, temp1);
- GetTokBlk(p2, start, temp2);
- } else {
- GetTokDel(p1, terminator, start, temp1);
- GetTokDel(p2, terminator, start, temp2);
- }
- p1 = temp1;
- p2 = temp2;
- break;
- }
-
- switch (method) {
- case ALPHABETICAL:
- result = strcmp(p1, p2);
- break;
- case CASE_FOLDED:
- result = stricmp(p1, p2);
- break;
- case NUMERICAL:
- result = atoi(p1);
- result -= atoi(p2);
- break;
- }
-
- /**
- | If the compared field matches, but the original records were
- | not identical, insert them in the order they came (p1 AFTER p2).
- **/
-
- if (!result) return 1;
- else return result;
- }
- #endif
-
- void CheckBreak(
- Boolean exitprog
- ){
-
- /**
- | Checks the CTRL-C flag and, the first time it is set, prints
- | a warning message. If the argument is True, frees allocated
- | memory and exits; no further action, if the argument is False.
- **/
- if (!abortProg && (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C))
- abortProg |= BREAK_DETECTED;
-
- if (abortProg) {
- if (!(abortProg & WARNING_PRINTED)) {
- puts("sort: *** BREAK ***");
- abortProg |= WARNING_PRINTED;
- }
- if (exitprog) {
- FreeTree(root);
- #ifndef SIMPLE
- if (temp1 != NULL) free(temp1);
- #endif
- if (fp != NULL) fclose(fp);
- exit(SYS_NORMAL_CODE);
- }
- }
- }
-
- int CXBRK(void)
- {
-
- /**
- | If a CTRL-C is detected from the operating system,
- | we silently defer all handling until "abortProg" is checked.
- **/
-
- abortProg |= BREAK_DETECTED;
- return 0;
- }
-
- static void DoTheStuff(
- FILE *filePointer
- ){
- char buffer[LINE_LENGTH];
-
- while (fgets(buffer, LINE_LENGTH, filePointer)) {
- CheckBreak(True);
-
- #ifdef BALANCED_TREE
- father = NULL;
- critical = root;
- #endif
-
- root = InsertTree(buffer, root);
-
- #ifdef BALANCED_TREE
- BalanceTree(buffer);
- #endif
-
- }
- }
-
- static void Syntax(void)
- {
-
- #ifdef SIMPLE
- puts("\nUsage: sort [-r] [file [file [ ... ] ] ]");
- #else
- puts("\nUsage: sort [-r][-f|-n][+N|-N][-tx] [file [file [ ... ] ] ]");
- #endif
-
- puts("Purpose: sorts the records read from the input file(s), or from");
- puts(" stdin, to stdout.");
- puts(" -r : reverse order sorting");
-
- #ifndef SIMPLE
- puts(" -n : numeric sorting \\ Default: alphabetic");
- puts(" -f : folds uppercase to lowercase / sorting");
- puts(" -N : sorts starting at column N \\ Default: start");
- puts(" +N : sorts respect to field N / at column 1");
- puts(" -t... : separator character(s) between fields (default: space)");
- #endif
-
- puts("");
- exit(SYS_NORMAL_CODE);
- }
-